Creating Prefixed Commands¶
Prefixed commands, called by Discord as "text commands" and sometimes called "message commands" (not to be confused with Context Menu Message Commands), are commands that are triggered when a user sends a normal message with a designated "prefix" in front of them.
Naming
While Discord themselves has used "text commands" to refer to these, we disagree with this naming. We think it is confusing, especially when referring to how Discord refers to slash commands (chat input commands). Thus, this library will use "prefixed commands", both in code and for its documentation.
While slash commands have been released, and is typically the way you should be making commands these days, there are many cases where the "legacy" commands may want to be kept due to various reasons, like wanting to use types not well-supported by Discord or to allow for greater flexibility for permission handling.
Whatever the reason is, interactions.py
has an extensive yet familiar prefixed command architecture ready to be used via a built-in extension.
Setup¶
Because prefixed commands are in their own extension, some setup is required. It usually is as simple as putting something like this in your main bot file:
1 2 3 4 5 6 7 8 |
|
By default, this will set up the bot to use prefixed commands and use mentioning the bot as the prefix (IE @bot hello). If you wish to change this, you have two options in setup
:
- If you want the bot to response to a static set of prefixes, you can use the
default_prefix
parameter to set the prefix to either a singular prefix or a list of prefixes. - If you want to dynamically determine which prefix(es) the bot should return to (say, based on the guild that the command is being run in), you can use the
generate_prefixes
parameter. The parameter takes in an asynchronous function that takes in theClient
and aMessage
, and returns a prefix or a list of prefixes.
Your First Prefixed Command¶
To create a prefixed command, simply define an asynchronous function and use the @prefixed_command()
(from interactions.ext.prefixed_commands
) decorator above it.
1 2 3 4 5 |
|
Command Name
If name
is not specified, interactions.py
will automatically use the function's name as the command's name.
If the bot's prefix was set to !
, then a user could invoke it like so:
Subcommands¶
Subcommands are rather simple, too:
1 2 3 4 5 6 7 |
|
A user can use them like so:
Parameters¶
Often, when using prefixed commands, you typically want to parse what the user says into separated parameters/arguments. This can be done easily in this library using a Python-esque syntax.
For example, to make a command that takes in one argument, we can do:
1 2 3 |
|
When a user uses the command, all they simply need to do is pass a word after the command:
If the user wishes to use multiple words in an argument like this, they can wrap it in quotes like so:
Forgetting Quotes
If a user forgets or simply does not wrap multiple words in an argument in quotes, the library will only use the first word for the argument and ignore the rest.
You can add as many parameters as you want to a command:
1 2 3 |
|
Variable and Consume Rest Arguments¶
There may be times where you wish for an argument to be able to have multiple words without wrapping them in quotes. There are two ways of approaching this.
Variable¶
If you wish to get a list (or more specifically, a tuple) of words for one argument, or simply want an undetermined amount of arguments for a command, then you should use a variable argument:
1 2 3 |
|
1 2 3 |
|
The result looks something like this:
Notice how the quoted words are still parsed as one argument in the tuple.
Consume Rest¶
If you simply wish to take in the rest of the user's input as an argument, you can use a consume rest argument, like so:
1 2 3 4 5 |
|
1 2 3 |
|
The result looks like this:
Quotes
If a user passes quotes into consume rest argument, then the resulting argument will have said quotes.
Parser ambiguities
Due to parser ambiguities, you can only have either a single variable or consume rest argument.
Typehinting and Converters¶
Basic Types¶
Parameters, by default, are assumed to be strings, since Message.content
, the content used for prefixed commands, is one. However, there are many times where you want to have a parameter be a more specific type, like an integer or boolean.
interactions.py
provides an easy syntax to do so:
1 2 3 |
|
Words/arguments will automatically be converted to the specified type. If interactions.py
is unable to convert it (a user could easily pass a letter into an_int
), then it will raise a BadArgument
error, which can be handled by an error handler. Error handling is handled similarly to how it is handled with slash commands.
You can even pass in a function for parameters:
1 2 3 4 5 6 |
|
Functions
If functions are used as arguments, they can either have one parameter (which is the passed argument as a string) or two parameters (which are the context and the argument). They can also be asynchronous or synchronous. Also, your typechecker will likely complain about this. You can ignore it for interactions.py
.
Booleans¶
Booleans, unlike other basic types, are handled somewhat differently, as using the default bool
converter would make any non-empty argument True
. It is instead evaluated as so:
1 2 3 4 |
|
Converters¶
Converters work much in the same way as they do for other commands; see the guide for converters for reference.
There are a few specific converters that only work with prefixed commands due to their nature, however.
Discord Converters¶
Prefixed commands can be typehinted with some Discord models, like so:
1 2 3 4 5 |
|
The argument here will automatically be converted into a Member
object:
A table of supported objects and their converters can be found here. You may use the Discord model itself in your command for prefixed commands, just like the above, and their respective converter will be used under the hood.
typing.Union
¶
typing.Union
allows for a parameter/argument to be of multiple types instead of one. interactions.py
will attempt to convert a given argument into each type specified (starting from the first one), going down the "list" until a valid match is found.
For example, the below will try to convert an argument to a GuildText
first, then a User
if it cannot do so.
1 2 3 4 5 6 |
|
Using |
for specifying a union is also supported, if you prefer it:
1 2 3 |
|
typing.Optional
¶
Usually, Optional[OBJECT]
is an alias for Union[OBJECT, None]
- it indicates the parameter can be passed None
or an instance of the object itself. It means something slightly different here, however.
If a parameter is marked as Optional
, then the command handler will try converting it to the type inside of it, defaulting to either None
or a default value, if found. A similar behavior is done is the value has a default value, regardless of if it is marked with Optional
or not.
For example, you could use the following code:
1 2 3 4 5 6 |
|
And if a user omits the delete_message_days
parameter, it would act as so:
typing.Literal
¶
typing.Literal
specifies that a parameter must be one of the values in the list. interactions.py
also forces that here (though this only works with values of basic types, like str
or int
):
1 2 3 4 5 |
|
Greedy
¶
The Greedy
class, included in this library, specifies interactions.py
to keep converting as many arguments as it can until it fails to do so. For example:
1 2 3 4 5 6 |
|
Greedy Warnings
Greedy
does not default to being optional. You must specify that it is by giving it a default value or wrapping it with Optional
. Greedy
, str
, None
, Optional
are also not allowed as parameters in Greedy
. Greedy
cannot be used as a variable or keyword-only argument.
Help Command¶
There is no automatically added help command in interactions.py
. However, you can use PrefixedHelpCommand
to create one with ease. Using it looks like so:
1 2 3 4 5 |
|
With the default options, the result looks like:
Other Notes¶
- Checks, cooldowns, and concurrency all work as-is with prefixed commands.
- Prefixed commands use a different method to process
Converter
s compared to slash commands. While they should roughly give the same result, they may act slightly differently. - All prefixed commands use
PrefixedContext
, which contains useful information based on the current instance of the command.